
package com.mayi.api.http;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.lang.ArrayUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.entity.GzipDecompressingEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpClientHelper {
    private static Logger logger = LoggerFactory.getLogger(HttpClientHelper.class);

    private static HttpClientHelper instance = null;

    private static Lock lock = new ReentrantLock();

    private CloseableHttpClient httpClient = null;

    private final static int MAX_TOTEL = 1000;

    private final static int MAX_CONNECTION_PER_ROUTE = 100;

    private HttpClientHelper() {
        instance = this;
    }

    public static HttpClientHelper getHttpClient() {
        if (instance == null) {
            lock.lock();
            try {
                if (instance == null) {
                    instance = new HttpClientHelper();
                    instance.init();
                }
            } finally {
                lock.unlock();
            }
        }

        return instance;
    }

    private void init() {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(MAX_TOTEL);
        cm.setDefaultMaxPerRoute(MAX_CONNECTION_PER_ROUTE);
        httpClient = HttpClientBuilder.create().setConnectionManager(cm).build();
    }

    public String execute(HttpRequestBase request, String charset) throws UnsupportedEncodingException {
        byte[] returnByte = executeAndReturnByte(request);
        if (ArrayUtils.isEmpty(returnByte)) {
            return null;

        }

        return new String(returnByte, charset);
    }

    public byte[] executeAndReturnByte(HttpRequestBase request) {
        byte[] rtn = new byte[0];

        if (request == null) {
            return rtn;
        }

        try {
            lock.lock();
            if (httpClient == null) {
                init();
            }
        } finally {
            lock.unlock();
        }

        if (httpClient == null) {
            logger.error("{}\nreturn error {}", request.getURI().toString(), "httpclient连接获取异常！");
            return rtn;
        }

        HttpEntity entity = null;
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(request);
            entity = response.getEntity();
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                logger.info("{}\nreturn correctly httpstatus code:{}", request.getURI().toString(),
                        statusCode);

                String encoding = ("" + response.getFirstHeader("Content-Encoding")).toLowerCase();
                if (encoding.indexOf("gzip") > 0) {
                    entity = new GzipDecompressingEntity(entity);
                }

                rtn = EntityUtils.toByteArray(entity);
            } else if (statusCode == 400) {
                rtn = EntityUtils.toByteArray(entity);
                logger.error("{}\nreturn error httpstatus code:{}", request.getURI().toString(), statusCode);
            } else {
                logger.error("{}\nreturn error httpstatus code:{}", request.getURI().toString(), statusCode);
            }

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            EntityUtils.consumeQuietly(entity);
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    logger.error("httpclient连接释放异常！", e);
                }
            }
        }

        return rtn;

    }

}
